#ifndef GsgXMLReader_defined
#define GsgXMLReader_defined

#include <strstream>

/// Read tiny xml elements and attributes
class GsgXMLReader : public GsgMeta
{
  /// type for stack of XML elements
  typedef std::vector<TiXmlElement *> elements_t;

  /// stack of XML elements
  elements_t elements;
  
  /// current element of speciifc type
  TiXmlElement *cur_element(const char *type_name)
  {
    if ( elements.back() != NULL )
    {
      return elements.back()->NextSiblingElement(type_name);
    } else
    {
      TiXmlElement *parent = elements[elements.size()-2];
      return parent->FirstChildElement(type_name);
    }
  }

  /// current element of any type
  TiXmlElement *cur_element()
  {
    if ( elements.back() != NULL )
    {
      return elements.back()->NextSiblingElement();
    } else
    {
      TiXmlElement *parent = elements[elements.size()-2];
      return parent->FirstChildElement();
    }
  }

public:
  /// constructor: start with the parent XML element
  GsgXMLReader(TiXmlElement *parent)
  {
    elements.push_back(parent);
  }
  
  /// begin reading a new xml ellement, return false if none available.
  bool begin_element(const char *type_name)
  {
    elements.back() = cur_element(type_name);
    return elements.back() != NULL;
  }

  /// not used
  void end_element()
  {
  }

  /// read simple float types
  void attr(const char *name, float &value)
  {
    double tmp;
    elements.back()->Attribute(name, &tmp);
    value = (float)tmp;
  }

  /// read simple int types
  void attr(const char *name, int &value)
  {
    elements.back()->Attribute(name, &value);
  }

  /// this templated attribute helper will work with many types  
  template <typename Type> void attr_helper(const char *name, Type *value, int n)
  {
    const char *src =
      name[0] != '\0' ?
      elements.back()->Attribute(name) : 
      elements.back()->GetText()
    ; 
    std::istrstream stream(src);
    for (int i = 0; i != n; ++i)
    {
      stream >> value[i];
    }
  }
  
  /// read float vector types
  void attr(const char *name, float *value, int n)
  {
    attr_helper(name, value, n);
  }
  
  /// read int vector types
  void attr(const char *name, int *value, int n)
  {
    attr_helper(name, value, n);
  }
  
  /// read string types
  void attr(const char *name, std::string &value)
  {
    value = elements.back()->Attribute(name);
  }

  /// go down one level
  void push()
  {
    elements.push_back(NULL);
  }

  /// go back up one level
  void pop()
  {
    elements.pop_back();
  }

  /// always true for a reader
  bool is_reading()
  {
    return true;
  }
  
  /// peek the next available element's type
  const char *cur_element_name()
  {
    return cur_element()->Value();
  }
};
#endif
